----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    05:03:27 04/03/2008 
-- Design Name: 
-- Module Name:    STAGE_EX - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_ARITH.ALL;
USE IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY STAGE_EX IS
  PORT (CLK           : IN  std_logic;
         RST          : IN  std_logic;
         IDEX_A       : IN  std_logic_vector(15 DOWNTO 0);
         IDEX_B       : IN  std_logic_vector(15 DOWNTO 0);
         IDEX_NPC     : IN  std_logic_vector(7 DOWNTO 0);
         IDEX_IR      : IN  std_logic_vector(31 DOWNTO 0);
         IDEX_IMM     : IN  std_logic_vector(15 DOWNTO 0);
         EXMEM_IR     : OUT std_logic_vector(31 DOWNTO 0);
         EXMEM_B      : OUT std_logic_vector(15 DOWNTO 0);
         EXMEM_COND   : OUT std_logic;
         EXMEM_ALUOUT : OUT std_logic_vector(15 DOWNTO 0));
END STAGE_EX;

ARCHITECTURE Behavioral OF STAGE_EX IS
BEGIN
  -- purpose: Perform executation stage
  -- type   : sequential
  -- inputs : CLK, RST, IDEX_A,IDEX_B,IDEX_NPC,IDEX_IR,IDEX_IMM
  -- outputs: EXMEM_IR, EXMEM_B, EXMEM_COND, EXMEM_ALUOUT
  PROCESS (CLK) IS
  BEGIN  -- PROCESS
    IF CLK'event AND CLK = '1' THEN     -- rising clock edge
      IF RST = '1' THEN                 -- synchronous reset (active high)
        EXMEM_IR     <= (OTHERS => '0');
        EXMEM_B      <= (OTHERS => '0');
        EXMEM_COND   <= '0';
        EXMEM_ALUOUT <= (OTHERS => '0');
      ELSE
        EXMEM_IR <= IDEX_IR;
        EXMEM_B  <= IDEX_B;
        IF IDEX_IR /= (31 DOWNTO 0 => '0') THEN
          CASE IDEX_IR(28 DOWNTO 26) IS
            WHEN "000" =>               -- ALU Instruction
              EXMEM_COND <= '0';
              CASE IDEX_IR(2 DOWNTO 0) IS
                WHEN "000" =>           -- Add
                  EXMEM_ALUOUT <= signed(IDEX_A) + signed(IDEX_B);
                WHEN "001" =>           -- Sub
                  EXMEM_ALUOUT <= signed(IDEX_A) - signed(IDEX_B);
                WHEN "010" =>           -- Set less than
                  IF IDEX_A < IDEX_B THEN
                    EXMEM_ALUOUT <= (OTHERS => '1');
                  ELSE
                    EXMEM_ALUOUT <= (OTHERS => '0');
                  END IF;
                WHEN "011" =>           -- BitOR
                  EXMEM_ALUOUT <= IDEX_A OR IDEX_B;
                WHEN "100" =>           -- BitAND
                  EXMEM_ALUOUT <= IDEX_A AND IDEX_B;
                WHEN OTHERS => NULL;
              END CASE;
            WHEN "001" =>               -- Load
              -- This allows for IDEX_A to be modified in a loop, using the same immediate as an offset
              EXMEM_COND   <= '0';
              EXMEM_ALUOUT <= signed(IDEX_A) + signed(IDEX_IMM);
            WHEN "010" =>               -- Store
              -- This allows for IDEX_A to be modified in a loop, using the same immediate as an offset
              EXMEM_COND   <= '0';
              EXMEM_ALUOUT <= signed(IDEX_A) + signed(IDEX_IMM);
            WHEN "011" =>               -- BEQ
              IF IDEX_A = IDEX_B THEN
                EXMEM_COND <= '1';
              ELSE
                EXMEM_COND <= '0';
              END IF;
              EXMEM_ALUOUT <= IDEX_IMM;  -- Note since we use 4 byte words, we just add the immediate
            WHEN "100" =>               -- BNE
              IF IDEX_A = IDEX_B THEN
                EXMEM_COND <= '0';
              ELSE
                EXMEM_COND <= '1';
              END IF;
              EXMEM_ALUOUT <= IDEX_IMM;  -- Note since we use 4 byte words, we just add the immediate
            WHEN "101" =>               -- Jump
              EXMEM_COND   <= '1';
              EXMEM_ALUOUT <= IDEX_IMM;
            WHEN "110" =>               -- LI - Load Immediate
              EXMEM_COND   <= '0';
              EXMEM_ALUOUT <= IDEX_IMM;
            WHEN OTHERS => NULL;
          END CASE;
        END IF;
      END IF;
    END IF;
  END PROCESS;
END Behavioral;

